/*
 * Created on 2005.11.2
 */
package lv.solcraft.replication.client.logging;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;

import lv.solcraft.replication.client.ClientConfig;
import lv.solcraft.replication.common.ReplicationConst;
import lv.solcraft.replication.common.server.SessionFacade;

import org.apache.log4j.Logger;
import org.apache.log4j.PatternLayout;
import org.apache.log4j.RollingFileAppender;

public class ClientLoggerImpl implements ClientLogger {

    private static final Logger log = Logger.getLogger(ClientLoggerImpl.class);

    public static final String LOG_PREFIX = "client.";

    private volatile Logger clientLog;

    private ClientConfig client;

    private SessionFacade sessionFacade;

    private Logger getClientLog() {
        if (clientLog == null) {
            clientLog = createLog4jLogger();
        }
        return clientLog;
    }

    private Logger createLog4jLogger() {
        Logger logger = Logger.getLogger(LOG_PREFIX + client.getName() + "." + client.getSiteId());
        logger.removeAllAppenders();
        RollingFileAppender fileAppender;
        try {
            fileAppender = new RollingFileAppender(new PatternLayout("%d %-5p %m%n"), new File(client.getConfig()
                    .getLogDir(), client.getName() + "-" + client.getSiteId() + ".log").getAbsolutePath());
            fileAppender.setBufferedIO(false);
            fileAppender.setImmediateFlush(true);
            fileAppender.setMaxBackupIndex(10);
        } catch (IOException e) {
            throw new RuntimeException("Failed to init file appender for client logger: " + client.getName());
        }
        logger.addAppender(fileAppender);
        return logger;
    }

    public void debugLocal(String msg) {
        logLocal(ReplicationConst.EVENT_TYPE_DEBUG, msg);
    }

    public void infoLocal(String msg) {
        logLocal(ReplicationConst.EVENT_TYPE_INFO, msg);
    }

    public void warnLocal(String msg) {
        logLocal(ReplicationConst.EVENT_TYPE_WARN, msg);
    }

    public void errorLocal(String msg) {
        logLocal(ReplicationConst.EVENT_TYPE_ERROR, msg);
    }

    public void debugAll(String msg) {
        logLocal(ReplicationConst.EVENT_TYPE_DEBUG, msg);
        logRemote(ReplicationConst.EVENT_TYPE_DEBUG, msg);
    }

    public void infoAll(String msg) {
        logLocal(ReplicationConst.EVENT_TYPE_INFO, msg);
        logRemote(ReplicationConst.EVENT_TYPE_INFO, msg);
    }

    public void warnAll(String msg) {
        logLocal(ReplicationConst.EVENT_TYPE_WARN, msg);
        logRemote(ReplicationConst.EVENT_TYPE_WARN, msg);
    }

    public void errorAll(String msg) {
        logLocal(ReplicationConst.EVENT_TYPE_ERROR, msg);
        logRemote(ReplicationConst.EVENT_TYPE_ERROR, msg);
    }

    protected void logLocal(int level, String msg) {
        String message = msg;
        if (level == ReplicationConst.EVENT_TYPE_DEBUG && getClientLog().isDebugEnabled()) {
            getClientLog().debug(message);
        } else if (level == ReplicationConst.EVENT_TYPE_INFO && getClientLog().isInfoEnabled()) {
            getClientLog().info(message);
        } else if (level == ReplicationConst.EVENT_TYPE_WARN) {
            getClientLog().warn(message);
        } else if (level == ReplicationConst.EVENT_TYPE_ERROR) {
            getClientLog().error(message);
        }
    }

    protected void logRemote(int level, String msg) {
        try {
            if (level >= client.getSettings().getLogLevel()) {
                sessionFacade.logEvent(client.getServerName(), ReplicationConst.getEventTypeAsString(level), client
                        .getSiteId(), msg);
            }
        } catch (Exception e) {
            log.warn("Error while sending log message to server, " + e.getMessage());
        }
    }

    public boolean isLocalDebugEnabled() {
        return getClientLog().isDebugEnabled();
    }

    public ClientConfig getClient() {
        return client;
    }

    public void setClient(ClientConfig client) {
        this.client = client;
    }

    public SessionFacade getSessionFacade() {
        return sessionFacade;
    }

    public void setSessionFacade(SessionFacade sessionFacade) {
        this.sessionFacade = sessionFacade;
    }

    public void errorAll(String msg, Throwable t) {
        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw);
        pw.println(msg);
        pw.println();
        t.printStackTrace(pw);
        logLocal(ReplicationConst.EVENT_TYPE_ERROR, sw.toString());
        logRemote(ReplicationConst.EVENT_TYPE_ERROR, sw.toString());
    }
}
